package com.jt.aop;

import com.jt.annotation.CacheFind;
import com.jt.util.ObjectMapperUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.ShardedJedis;


import java.util.Arrays;

@Component      //交给Spring容器管理
@Aspect         //标识AOP切面类
public class RedisAOP {

    @Autowired
    private JedisCluster jedis;
    //private JedisSentinelPool sentinelPool;
    //private ShardedJedis jedis;
    //private Jedis jedis;

    //1. 定义切入点表达式     2.定义通知方法


    /**
     * 实现AOP缓存:
     *      1.准备key = 获取key的前缀 + "动态拼接参数"
     *      2.从redis中获取数据
     *              结果1:  没有数据,查询数据库,之后将数据保存到缓存中
     *              结果2:  有数据,  直接将缓存数据返回
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("@annotation(cacheFind)")
    public Object around(ProceedingJoinPoint joinPoint, CacheFind cacheFind) throws Throwable {
        //从池中, 动态获取数据
        //Jedis jedis = sentinelPool.getResource();

        String perkey = cacheFind.key();
        String args = Arrays.toString(joinPoint.getArgs());
        String key = perkey + "::" + args;
        Object result = null;
        //2.判断redis中是否有数据
        if(jedis.exists(key)){
           String json = jedis.get(key);
           //利用工具API动态获取返回值类型
           MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
           Class returnType = methodSignature.getReturnType();
           //如果采用object.class形式 则只能转化简单对象,不能转化嵌套对象
           result = ObjectMapperUtil.toObj(json,returnType);
           System.out.println("AOP查询Redis缓存!!!");
        }else{
            //表示缓存中没有数据,应该查询数据库动态获取
            result = joinPoint.proceed();    //调用下一个通知/目标方法
            //应该将数据保存到缓存中
            String json = ObjectMapperUtil.toJSON(result);
            if(cacheFind.seconds()>0){
                jedis.setex(key, cacheFind.seconds(), json);
            }else{
                jedis.set(key,json);
            }
            System.out.println("AOP查询数据库!!!");
        }

        //jedis.close();  //关闭链接
        return result;
    }










    //1.定义切入点表达式
    //@Pointcut("bean(itemCatServiceImpl)")
    //@Pointcut("within(com.jt.service.*)")  //按照某个类匹配
   /* @Pointcut("execution(* com.jt.service.*.*(..))")
    public void pointCut(){

    }

    //joinPoint连接点???????
    @Before("pointCut()")
    public void before(JoinPoint joinPoint){
        Class targetClass = joinPoint.getTarget().getClass();
        Object[] args = joinPoint.getArgs();
        String methodName = joinPoint.getSignature().getName();
        String ClassName = joinPoint.getSignature().getDeclaringTypeName();
        System.out.println("获取目标对象的类型:"+targetClass);
        System.out.println("获取目标参数:"+ Arrays.toString(args));
        System.out.println("获取目标方法名称:"+ methodName);
        System.out.println("获取目标类的路径:"+ ClassName);
        System.out.println("我是前置通知!!!");
    }*/
}
